﻿using System;
using System.Collections;
using System.Data;
using System.IO;
using System.Text;
using System.Xml;

namespace AbpCodeBuilder.CodeHelper
{
    public class CodeCommon
    {
        private static readonly string Datatypefile = AppDomain.CurrentDomain.BaseDirectory.TrimEnd(new char[1]
        {
            '\\'
        }) + "\\DatatypeMap.cfg";

        #region 文件读取

        public static string Read(string path)
        {
            using (StreamReader sr = new StreamReader(path, Encoding.Default))
            {
                StringBuilder sb = new StringBuilder();

                String line;
                while ((line = sr.ReadLine()) != null)
                {
                    sb.AppendLine(line);
                }
                return sb.ToString();
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="filePath">文件保存路径</param>
        /// <param name="fileName">文件名</param>
        /// <param name="templateContent">模板内容</param>
        public static void Write(string filePath, string fileName, string templateContent)
        {
            if (!Directory.Exists(filePath))
            {
                Directory.CreateDirectory(filePath);
            }

            using (FileStream fs = new FileStream(Path.Combine(filePath, fileName), FileMode.Create))
            {
                //获得字节数组
                byte[] data = Encoding.UTF8.GetBytes(templateContent);
                //开始写入
                fs.Write(data, 0, data.Length);
            }

        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="filePath">文件保存路径</param>
        /// <param name="templateContent">模板内容</param>
        public static void Write(string filePath, string templateContent)
        {
            using (FileStream fs = new FileStream(filePath, FileMode.Create))
            {
                //获得字节数组
                byte[] data = Encoding.UTF8.GetBytes(templateContent);
                //开始写入
                fs.Write(data, 0, data.Length);
            }
        }

        #endregion

        #region 首字母小写

        /// <summary>
        /// 首字母小写
        /// </summary>
        /// <returns></returns>
        public static string GetFirstToLowerStr(string source)
        {
            if (!string.IsNullOrEmpty(source))
            {
                if (source.Length > 1)
                {
                    return char.ToLower(source[0]) + source.Substring(1);
                }
                return char.ToLower(source[0]).ToString();
            }
            return "";
        }

        #endregion

        #region 移除最后一个S

        /// <summary>
        /// 移除最后一个S
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static string RemoveLastS(string source)
        {
            if (!string.IsNullOrWhiteSpace(source))
            {
                source = source.Substring(0, source.Length - 1);

                return source;
            }
            return "";
        }

        #endregion

        #region SqlLite数据库类型映射到C#类型
        public static string SQLiteTypeToCS(string type)
        {
            string str = "string";
            if (File.Exists(Datatypefile))
            {
                string valueFromCfg = GetValueFromCfg(CodeCommon.Datatypefile, "SQLiteType", type.ToLower().Trim());
                str = valueFromCfg != "" ? valueFromCfg : type.ToLower().Trim();
            }
            return str;
        } 
        #endregion

        #region Sql Server数据库类型映射到C#类型
        /// <summary>
        /// Sql Server数据库类型映射到C#类型
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static string DbTypeToCS(string type)
        {
            string str = "string";
            if (File.Exists(Datatypefile))
            {
                string valueFromCfg = GetValueFromCfg(CodeCommon.Datatypefile, "DbToCS", type.ToLower().Trim());
                str = valueFromCfg != "" ? valueFromCfg : type.ToLower().Trim();
            }
            return str;
            }
        #endregion//---------------------------------------------------------------------- 

        #region 类型转换到SQL
        /// <summary>
        /// 类型转换到SQL
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static string DbTypeToSQL(string type)
        {
            switch (type)
            {
                // Summary:
                //     System.Int64. A 64-bit signed integer.
                case "bigint":
                    type = "BigInt";
                    break;
                //
                // Summary:
                //     System.Array of type System.Byte. A fixed-length stream of binary data ranging
                //     between 1 and 8,000 bytes.
                case "binary":
                    type = "Binary";
                    break;
                //
                // Summary:
                //     System.Boolean. An unsigned numeric value that can be 0, 1, or null.
                case "bit":
                    type = "Bit";
                    break;

                //
                // Summary:
                //     System.String. A fixed-length stream of non-Unicode characters ranging between
                //     1 and 8,000 characters.
                case "char":
                    type = "Char";
                    break;
                //
                // Summary:
                //     System.DateTime. Date and time data ranging in value from January 1, 1753
                //     to December 31, 9999 to an accuracy of 3.33 milliseconds.
                case "datetime":
                    type = "DateTime";
                    break;
                //
                // Summary:
                //     System.Decimal. A fixed precision and scale numeric value between -10 38
                //     -1 and 10 38 -1.
                case "decimal":
                    type = "Decimal";
                    break;
                //
                // Summary:
                //     System.Double. A floating point number within the range of -1.79E +308 through
                //     1.79E +308.
                case "float":
                    type = "Float";
                    break;
                //
                // Summary:
                //     System.Array of type System.Byte. A variable-length stream of binary data
                //     ranging from 0 to 2 31 -1 (or 2,147,483,647) bytes.
                case "image":
                    type = "Image";
                    break;
                //
                // Summary:
                //     System.Int32. A 32-bit signed integer.
                case "int":
                    type = "Int";
                    break;
                //
                // Summary:
                //     System.Decimal. A currency value ranging from -2 63 (or -9,223,372,036,854,775,808)
                //     to 2 63 -1 (or +9,223,372,036,854,775,807) with an accuracy to a ten-thousandth
                //     of a currency unit.
                case "money":
                    type = "Money";
                    break;
                //
                // Summary:
                //     System.String. A fixed-length stream of Unicode characters ranging between
                //     1 and 4,000 characters.
                case "nchar":
                    type = "NChar";
                    break;
                //
                // Summary:
                //     System.String. A variable-length stream of Unicode data with a maximum length
                //     of 2 30 - 1 (or 1,073,741,823) characters.
                case "ntext":
                    type = "NText";
                    break;
                //
                // Summary:
                //     System.String. A variable-length stream of Unicode characters ranging between
                //     1 and 4,000 characters. Implicit conversion fails if the string is greater
                //     than 4,000 characters. Explicitly set the object when working with strings
                //     longer than 4,000 characters.
                case "nvarchar":
                    type = "NVarChar";
                    break;
                //
                // Summary:
                //     System.Single. A floating point number within the range of -3.40E +38 through
                //     3.40E +38.
                case "real":
                    type = "Real";
                    break;
                //
                // Summary:
                //     System.Guid. A globally unique identifier (or GUID).
                case "uniqueidentifier":
                    type = "UniqueIdentifier";
                    break;
                //
                // Summary:
                //     System.DateTime. Date and time data ranging in value from January 1, 1900
                //     to June 6, 2079 to an accuracy of one minute.
                case "smalldatetime":
                    type = "SmallDateTime";
                    break;
                //
                // Summary:
                //     System.Int16. A 16-bit signed integer.
                case "smallint":
                    type = "SmallInt";
                    break;
                //
                // Summary:
                //     System.Decimal. A currency value ranging from -214,748.3648 to +214,748.3647
                //     with an accuracy to a ten-thousandth of a currency unit.
                case "smallmoney":
                    type = "SmallMoney";
                    break;
                //
                // Summary:
                //     System.String. A variable-length stream of non-Unicode data with a maximum
                //     length of 2 31 -1 (or 2,147,483,647) characters.
                case "text":
                    type = "Text";
                    break;
                //
                // Summary:
                //     System.Array of type System.Byte. Automatically generated binary numbers,
                //     which are guaranteed to be unique within a database. timestamp is used typically
                //     as a mechanism for version-stamping table rows. The storage size is 8 bytes.
                case "timestamp":
                    type = "Timestamp";
                    break;
                //
                // Summary:
                //     System.Byte. An 8-bit unsigned integer.
                case "tinyint":
                    type = "TinyInt";
                    break;
                //
                // Summary:
                //     System.Array of type System.Byte. A variable-length stream of binary data
                //     ranging between 1 and 8,000 bytes. Implicit conversion fails if the byte
                //     array is greater than 8,000 bytes. Explicitly set the object when working
                //     with byte arrays larger than 8,000 bytes.
                case "varbinary":
                    type = "VarBinary";
                    break;
                //
                // Summary:
                //     System.String. A variable-length stream of non-Unicode characters ranging
                //     between 1 and 8,000 characters.
                case "varchar":
                    type = "VarChar";
                    break;
                //
                // Summary:
                //     System.Object. A special data type that can contain numeric, string, binary,
                //     or date data as well as the SQL Server values Empty and Null, which is assumed
                //     if no other type is declared.
                case "variant":
                    type = "Variant";
                    break;
                //
                // Summary:
                //     An XML value. Obtain the XML as a string using the System.Data.SqlClient.SqlDataReader.GetValue(System.Int32)
                //     method or System.Data.SqlTypes.SqlXml.Value property, or as an System.Xml.XmlReader
                //     by calling the System.Data.SqlTypes.SqlXml.CreateReader() method.
                case "xml":
                    type = "Xml";
                    break;
                //
                // Summary:
                //     A SQL Server 2005 user-defined type (UDT).
                case "udt":
                    type = "Udt";
                    break;
                //
                // Summary:
                //     A special data type for specifying structured data contained in table-valued
                //     parameters.
                case "structured":
                    type = "Structured";
                    break;
                //
                // Summary:
                //     Date data ranging in value from January 1,1 AD through December 31, 9999
                //     AD.
                case "date":
                    type = "Date";
                    break;
                //
                // Summary:
                //     Time data based on a 24-hour clock. Time value range is 00:00:00 through
                //     23:59:59.9999999 with an accuracy of 100 nanoseconds.
                case "time":
                    type = "Time";
                    break;
                //
                // Summary:
                //     Date and time data. Date value range is from January 1,1 AD through December
                //     31, 9999 AD. Time value range is 00:00:00 through 23:59:59.9999999 with an
                //     accuracy of 100 nanoseconds.
                case "datetime2":
                    type = "DateTime2";
                    break;
                //
                // Summary:
                //     Date and time data with time zone awareness. Date value range is from January
                //     1,1 AD through December 31, 9999 AD. Time value range is 00:00:00 through
                //     23:59:59.9999999 with an accuracy of 100 nanoseconds. Time zone value range
                //     is 0-14:00 through +14:00.
                case "datetimeoffset":
                    type = "DateTimeOffset";
                    break;
                default:
                    break;
            }
            return type;
        } 
        #endregion

        #region 重载大写方法
        public static string ToUpper(string fileName)
        {
            return fileName.Substring(0, 1).ToUpper() + fileName.Substring(1);
        }
        #endregion

        #region 判断Null值
        public static T IsNull<T>(DataRow dr, string field, T d = default (T))
        {
            if (dr[field] == DBNull.Value)
                return d;
            else
                return (T)dr[field];
        } 
        #endregion

        #region 判断类型是否为可空类型
        public static bool isValueType(string cstype)
        {

            bool flag = false;
            if (File.Exists(Datatypefile))
            {
                string valueFromCfg = GetValueFromCfg(CodeCommon.Datatypefile, "ValueType", cstype.Trim());
                if (valueFromCfg == "true" || valueFromCfg == "是")
                    flag = true;
            }
            return flag;
        } 
        #endregion

        #region 获取DatatypeMap配置文件的值
        public static string GetValueFromCfg(string filename, string xpathTypeName, string Key)
        {
            try
            {
                Hashtable hashtable = new Hashtable();
                XmlDocument xmlDocument = new XmlDocument();
                xmlDocument.Load(filename);
                XmlNode xmlNode1 = xmlDocument.SelectSingleNode("Map/" + xpathTypeName);
                if (xmlNode1 != null)
                {
                    foreach (XmlNode xmlNode2 in xmlNode1.ChildNodes)
                        hashtable.Add((object)xmlNode2.Attributes["key"].Value, (object)xmlNode2.Attributes["value"].Value);
                }
                object obj = hashtable[(object)Key];
                if (obj != null)
                    return obj.ToString();
                else
                    return "";
            }
            catch (Exception ex)
            {
                throw new Exception("Load DatatypeMap file fail:" + ex.Message);
            }
        } 
        #endregion

    }
}